package cn.itcast.dewu.rabbitUtils;

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.json.JSONUtil;
import cn.itcast.dewu.dto.JavaEmailDTO;
import cn.itcast.dewu.pojo.*;
import cn.itcast.dewu.dto.FollowType;
import cn.itcast.dewu.service.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.carrotsearch.hppc.ShortIntMap;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

import java.io.IOException;

import static cn.itcast.dewu.utils.RedisConstants.LOCK_SPECIALGOODS_KEY;
import static cn.itcast.dewu.utils.RedisConstants.VOUCHER_LOCAK_KEY;

@Component
@Slf4j
public class RabbitLiener {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private VoucherOrderService voucherOrderService;
    @Autowired
    private BlogCommentsService blogCommentsService;
    @Autowired
    private SeckillVoucherService seckillVoucherService;
    @Autowired
    private UserInfoService userInfoService;


    /*
     *
     * ================================================
     * 处理优惠券订单
     * */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue("voucher.orderqueue")
            , exchange = @Exchange(value = "voucher.orderexchange", type = ExchangeTypes.DIRECT)
            , key = "voucher.order"
    ))
    public void consumeVoucherOrder(VoucherOrder voucherOrder) {
        //        System.err.println(1/0);

        //处理订单
        createVoucherOrder(voucherOrder);
    }

    @Transactional
    public void createVoucherOrder(VoucherOrder voucherOrder) {
        //获取用户id

        Long userId = voucherOrder.getUserId();
        //获取订单id
        Long voucherId = voucherOrder.getVoucherId();
        //获取锁
        RLock rLock = redissonClient.getLock(VOUCHER_LOCAK_KEY + voucherId);
        if (!rLock.tryLock()) {//waitTime 默认为-1 不等待,leaseTime 超时时间 默认30s
            log.error("不允许重复下单");
            return;
        }

        try {  //查询订单
            Integer count = voucherOrderService.query().eq("user_id", userId)
                    .count();
            if (count > 0) {
                log.error("不允许重复下单");
                return;
            }
            //减库存
            boolean falg = seckillVoucherService.update()
                    .eq("voucher_id", voucherId)
                    .gt("stock", 0)
                    .setSql("stock = stock - 1")
                    .update();

            if (!falg) {
                throw new RuntimeException();
            }
            //增加订单
            boolean save = voucherOrderService.save(voucherOrder);
            if (!save) {
                throw new RuntimeException();
            }
        } finally {
            rLock.unlock();
        }

    }

    /*
     *=====================================================
     *删除评论有关播客的评论
     * */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue("delete.blog.queue")
            , exchange = @Exchange(value = "delete.blog.exchange", type = ExchangeTypes.DIRECT)
            , key = "delete.blog"
    ))
    public void consumedeleteBlog(Long id) {
        //删除评论有关播客的评论
        LambdaQueryWrapper<BlogComments> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BlogComments::getBlogId, id);
        boolean remove = blogCommentsService.remove(queryWrapper);
        if (remove) {
            DeleteRequest request = new DeleteRequest("goods_index", id.toString());

            try {
                client.delete(request, RequestOptions.DEFAULT);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /*
    ===========================================================================
     * 关注与取消关注
     * */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue("follow.user.queue")
            , exchange = @Exchange(value = "userinfo.follow.exchange", type = ExchangeTypes.DIRECT)
            , key = "userinfo.follow"
    ))
    public void followUser(FollowType followType) {
        Boolean isFollow = followType.getIsFollow();
        Long userId = followType.getUserId();
        Long followUserId = followType.getFollowUserId();
        /*
         * 是关注的话
         * 被关注的人粉丝加一
         * 当前用户关注人的数量 +1 */
        if (BooleanUtil.isTrue(isFollow)) {

            userInfoService.update().eq("user_id", userId)
                    .setSql("followee = followee + 1").update();
            userInfoService.update().eq("user_id", followUserId)
                    .setSql("fans = fans + 1").update();
            return;
        }
        /*
         * 是取消关注的话
         * 被关注的人粉丝-1
         * 当前用户关注人的数量 -11 */
        userInfoService.update().eq("id", userId)
                .setSql("followee = followee - 1").update();
        userInfoService.update().eq("id", followUserId)
                .setSql("fans = fans - 1").update();
    }

    //处理失败信息的消费者
    @RabbitListener(queues = "errqueue")
    public void consumerErrMessage(Object object) {
        System.err.println(object);
        log.error("消息处理错误,将发送信息给管理员");
    }


    /*
     * =========================================================================
     * 购买特价商品
     * */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue("specialgoods.orderqueue")
            , exchange = @Exchange(value = "specialgoods.orderexchange", type = ExchangeTypes.DIRECT)
            , key = "specialgoods.order"
    ))
    public void consumeVoucherOrder(GoodsOrder goodsOrder) {
        //        System.err.println(1/0);

        //处理订单
        createGoodsOrder(goodsOrder);
    }

    @Autowired
    private GoodsOrderService goodsOrderService;
    @Autowired
    private GoodsService goodsService;

    /*
     * ==============================================================
     * 创建商品订单
     *
     * */
    @Transactional
    public void createGoodsOrder(GoodsOrder goodsOrder) {
        //获取用户id
        Long userId = goodsOrder.getUserId();
        //获取订单id
        Long goodsId = goodsOrder.getGoodsId();
        //获取锁
        RLock rLock = redissonClient.getLock(LOCK_SPECIALGOODS_KEY + goodsId);
        if (!rLock.tryLock()) {//waitTime 默认为-1 不等待,leaseTime 超时时间 默认30s
            log.error("特价商品,不允许重复下单");
            return;
        }

        try {  //查询订单
            Integer count = goodsOrderService.query().eq("user_id", userId)
                    .count();
            if (count > 0) {
                log.error("不允许重复下单");
                return;
            }
            //减库存
            boolean falg = goodsService.update()
                    .eq("id", goodsId)
                    .gt("stock", 0)
                    .setSql("stock = stock - 1")
                    .update();

            if (!falg) {
                throw new RuntimeException();
            }
            //增加订单
            boolean save = goodsOrderService.save(goodsOrder);
            if (!save) {
                throw new RuntimeException();
            }
            goodsService.update().setSql("sold = sold+1").update();
        } finally {
            rLock.unlock();
        }

    }

    @Resource
    private RestHighLevelClient client;

    /*
     * ======================================================
     * 添加商品后更新ES索引库
     * */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue("goods.saveGoodsQueue")
            , exchange = @Exchange(value = "goods.saveGoods.exchange", type = ExchangeTypes.DIRECT)
            , key = "goods.saveGoods"
    ))
    public void saveGoods(Goods goods) {
        try {
            //将goods转换成json

            String jsonStr = JSONUtil.toJsonStr(goods);
            //准备发送请求
            IndexRequest request = new IndexRequest("goods_index").id(goods.getId().toString());
            request.source(jsonStr, XContentType.JSON);
            client.index(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*
     * ======================================================
     *删除商品后更新ES索引库
     * */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue("goods.deleteGoodsQueue")
            , exchange = @Exchange(value = "goods.delete.exchange", type = ExchangeTypes.DIRECT)
            , key = "goods.delete"
    ))
    public void deleteGoodsById(Long id) {
        DeleteRequest request = new DeleteRequest("goods_index", id.toString());

        try {
            client.delete(request, RequestOptions.DEFAULT);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /*
     * ======================================================
     *添加播客后更新ES索引库
     * */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue("blog.save.queue")
            , exchange = @Exchange(value = "blog.save.exchange", type = ExchangeTypes.DIRECT)
            , key = "blog.save"
    ))
    public void saveBlog(Blog blog) {
        try {
            //将goods转换成json
            String jsonStr = JSONUtil.toJsonStr(blog);
            //准备发送请求
            IndexRequest request = new IndexRequest("goods_index").id(blog.getId().toString());
            request.source(jsonStr, XContentType.JSON);
            client.index(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /*
     * ======================================================
     *发送邮件 里面包含验证码
     * */
    @Autowired
    private JavaMailSender javaMailSender;
    //    创建发送人
    private static final String from = "1163363983@qq.com";
    private static final String subject = "你的登录验证码";
    //    创建接受人
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue("java.mail.queue")
            , exchange = @Exchange(value = "java.mail.exchange", type = ExchangeTypes.DIRECT)
            , key = "java.mail"
    ))
    public void sendCode(JavaEmailDTO emailDTO) {
        final String to = emailDTO.getEmail();
        SimpleMailMessage message = new SimpleMailMessage();
                message.setFrom(from);
                message.setTo(to);
                message.setSubject(subject);
                message.setText(emailDTO.getCode());
                javaMailSender.send(message);
    }
}
